local delay = 100  -- in seconds
local log = ngx.log
local ERR = ngx.ERR
local check
cjson = require "cjson.safe"
local http2tcp = require "http2tcp"
local redis = require "resty.redis"
local stats_redis_key = "dist-wrk-stats"
local running_taskid_redis_key = "dist-wrk-running-taskid-list"


local function save_detail_metric(db, taskid, detail)
    local metric = {"qps", "connections", "latency", "err_biz", "err_read", "err_connect", "err_status", "err_timeout", "err_write", "requests"}
    for _, metric_name in pairs(metric) do 
        local resp = {}
        for path, v in pairs(detail) do 
            local target = path
            local datapoints = {}
            for _, item in pairs(v) do 
                table.insert(datapoints, {item[metric_name], item.x})
            end
            table.insert(resp, {target = target, datapoints = datapoints})
        end

        local field = string.format("%s-%s", taskid, metric_name)
        red:hset(stats_redis_key, field, cjson.encode(resp))
    end
end

local function save_overview_metric(db, taskid, overview)
    local metric = {"RecvRate", "send", "SendRate", "recv", "runtime", "requests", "complete"}
    for _, metric_name in pairs(metric) do 
        local new_value = overview[metric_name] or 0
        local sql = string.format([[
            insert into wrk_metric_tab set 
            task_id=%s,
            target='%s',
            metric_name='%s',
            metric_value=%s,
            timestamp_ms=%s,
            ctime=Now()
        ]], taskid, metric_name, metric_name, new_value, os.time()*1000)

        local res, err, errno, sqlstate = db:query(sql)  
        if not res then  
            print("select error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)  
            return  
        end  
    end
end

local function save_percent_metric(red, taskid, percent)
    local metric = {"25.0", "50.0", "75.0", "90.0", "99.0"}
    for _, path in pairs(percent) do 
        local r = percent[path].latency
        for _, metric_name in pairs(metric) do 
            local new_value = r[metric_name]
            local field = string.format("%s-latency-P%s", taskid, metric_name)
            local tb = cjson.decode(red:hget(stats_redis_key, field))
            if not tb then 
                tb = {
                    {
                        target = path,
                        datapoints = {}
                    }
                }
            end
            table.insert(tb[1].datapoints, {new_value, os.time() * 1000})
            red:hset(stats_redis_key, field, cjson.encode(tb))
        end 
    end
end

handler = function()
    local mysql = require("resty.mysql")  
    local db, err = mysql:new()  
    if not db then  
        ngx.say("new mysql error : ", err)  
        return  
    end  

    db:set_timeout(1000)  
    
    local props = {  
        host = "127.0.0.1",  
        port = 3306,  
        database = "att",  
        user = "root",  
        password = "Lzslov123!"
    }  
    
    local res, err, errno, sqlstate = db:connect(props)  

    local sql = "select id from wrk_task_tab where status='running'"
    res, err, errno, sqlstate = db:query(sql)  
    if not res then  
        print("select error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)  
        return  
    end  

    -- print(cjson.encode(res))
    for _, v in pairs(res) do 
        local taskid = tonumber(v.id)
        http2tcp:new("127.0.0.1", 9877)
        local cmd    = "stats"
        local is_force = 0
        local body = ""
        http2tcp:send(taskid, cmd, is_force, body)
        local data = http2tcp:receive()
        -- if data.stop ==1 then 
        --     sql = string.format("update wrk_task_tab set status='stop' where task_id=%s", taskid)
        --     db:query(sql)  
        -- end

        -- save_detail_metric(db, taskid, data.detail)
        save_overview_metric(db, taskid, data.overview)
        -- save_percent_metric(db, taskid, data.percent)
    end
end

log(ERR, ngx.worker.id())
if 0 == ngx.worker.id() then
    local ok, err = ngx.timer.every(delay, handler)
    if not ok then
        log(ERR, "failed to create timer: ", err)
        return
    end
end